package cfengMiddleware.server.service.impl;

import CfengMiddleWare.model.entity.MidGoods;
import CfengMiddleWare.model.mapper.MidGoodsMapper;
import cfengMiddleware.server.service.MidGoodsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Strings;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 商品信息表 服务实现类
 * </p>
 *
 * @author cfeng
 * @since 2022-09-12
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class MidGoodsServiceImpl extends ServiceImpl<MidGoodsMapper, MidGoods> implements MidGoodsService {

    private final  MidGoodsMapper midGoodsMapper;

    private final ObjectMapper objectMapper;

    //redis模板
    private final RedisTemplate redisTemplate;

    //redis存储的命名的前缀
    private static final String keyPerfix = "goods:";

    /**
     * 获取商品，优先从Cache中获取，Cache中没有，再从数据库中查询，并且塞入Cache中
     * 为了解决缓存穿透，当数据库中也不存在数据时，将null放入缓存中，设置过期时间
     */
    @Override
    public MidGoods getGoodsInfo(String goodsCode)  throws Exception{
        //定义商品对象
        MidGoods goods = null;
        //缓存中的key
        final String key = keyPerfix + goodsCode;
        //Redis的操作组件
        ValueOperations valueOperations = redisTemplate.opsForValue();
        //业务逻辑
        if(redisTemplate.hasKey(key)) {
            log.info("获取商品：Cache中存在，商品编号:{}",goodsCode);
            //缓存中获取
            Object res = valueOperations.get(key);
            //找到就进行解析返回
            if(res != null && !Strings.isNullOrEmpty(res.toString())) {
                goods = objectMapper.convertValue(res,MidGoods.class); //JSON格式序列化
            }
        } else {
            //在数据库中查询
            log.info("该商品不在Cache中");
            goods = midGoodsMapper.selectByCode(goodsCode);
            if(goods != null) {
                //数据库中找到该商品，写入缓存，局部性原理
                valueOperations.set(key,objectMapper.writeValueAsString(goods));
            } else {
                //缓存穿透发生的情况，为了避免，这里也将其写入缓存中，当然需要设置过期的时间，这里假设30min
                valueOperations.set(key,"",30L, TimeUnit.MINUTES); //没有查询到，空字符串null
            }
        }
        return goods;
    }
}
